package org.tagging.service.impl.indonesian;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.tagging.dao.indonesian.IndonesianMapper;
import org.tagging.model.AbbreviationIndonesian;
import org.tagging.model.TaggingIndonesian;
import org.tagging.model.UnknownWordIndonesian;
import org.tagging.service.TaggingService;
import org.tagging.service.impl.other.ClientUserServiceImpl;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class IndonesianServiceImpl implements TaggingService<TaggingIndonesian> {
    @Resource
    private IndonesianMapper indonesianMapper;
    @Autowired
    private AbbreviationIndonesianServiceImpl abbreviationService;
    @Autowired
    private UnknownWordIndonesianServiceImpl unknownWordService;
    @Autowired
    private ClientUserServiceImpl userDetailsService;

    @Override
    public List<TaggingIndonesian> list(Integer size) {
        List<TaggingIndonesian> taggingIndonesians = indonesianMapper.listNotUsingAndUpdated(size);
        updateUsingBy(taggingIndonesians);
        return taggingIndonesians;
    }

    @Override
    public List<TaggingIndonesian> listNotTranslate(Integer size) {
        List<TaggingIndonesian> taggingIndonesians = indonesianMapper.listNotUsingAndTranslated(size);
        updateUsingBy(taggingIndonesians);
        return taggingIndonesians;
    }

    @Override
    public List<TaggingIndonesian> listNotAbbreviate(Integer size) {
        List<TaggingIndonesian> taggingIndonesians = indonesianMapper.listNotUsingAndAbbreviated(size);
        updateUsingBy(taggingIndonesians);
        return taggingIndonesians;
    }

    @Override
    public List<TaggingIndonesian> listNotUnknownWord(Integer size) {
        List<TaggingIndonesian> taggingIndonesians = indonesianMapper.listNotUsingAndUnknownWorded(size);
        updateUsingBy(taggingIndonesians);
        return taggingIndonesians;
    }

    @Override
    public void clearUsingBy(Integer tagId) {
        TaggingIndonesian indonesian = new TaggingIndonesian();
        indonesian.setId(tagId);
        indonesian.setUsingBy(-1);
        indonesianMapper.updateSelective(indonesian);
    }

    @Override
    public void translate(Integer id, String translation) {
        TaggingIndonesian taggingIndonesian = new TaggingIndonesian();
        taggingIndonesian.setId(id);
        taggingIndonesian.setExampleChineseManual(translation);
        updateSelective(taggingIndonesian);
    }

//    public void updateUpdateByAbbreviation(Integer tagId) {
//        TaggingIndonesian indonesian = new TaggingIndonesian();
//        Integer userId = userDetailsService.retrieveCurrentUserId();
//        indonesian.setUpdateBy(userId);
//        indonesian.setUpdateByAbbreviation(userId);
//        indonesian.setId(tagId);
//        updateSelective(indonesian);
//        //每更新一条记录，说明用户提交了一条记录
//        userDetailsService.incrementComplete("indonesian");
//    }


    @Override
    public void updateUpdateByAndTranslated(Integer id) {
        Integer userId = userDetailsService.retrieveCurrentUserId();
        TaggingIndonesian indonesian = new TaggingIndonesian();
        indonesian.setId(id);
        indonesian.setUpdateBy(userId);
        indonesian.setUpdateByTranslation(userId);
        updateSelective(indonesian);
    }

    @Override
    public void updateUpdateByAndAbbreviation(Integer tagId) {
        Integer userId = userDetailsService.retrieveCurrentUserId();
        TaggingIndonesian indonesian = new TaggingIndonesian();
        indonesian.setUpdateBy(userId);
        indonesian.setId(tagId);
        indonesian.setUpdateByAbbreviation(userId);
        updateSelective(indonesian);
    }

    @Override
    public void updateUpdateByAndUnknownWord(Integer tagId) {
        Integer userId = userDetailsService.retrieveCurrentUserId();
        TaggingIndonesian indonesian = new TaggingIndonesian();
        indonesian.setUpdateBy(userId);
        indonesian.setId(tagId);
        indonesian.setUpdateByUnknownWord(userId);
        updateSelective(indonesian);
    }

    @Override
    public void updateSelective(TaggingIndonesian indonesian) {
        indonesian.setUpdateTime(LocalDateTime.now());
        indonesianMapper.updateSelective(indonesian);
    }

    void updateUsingBy(List<TaggingIndonesian> taggingIndonesians) {
        Integer userId = userDetailsService.retrieveCurrentUserId();
        TaggingIndonesian tmp = new TaggingIndonesian();
        for (TaggingIndonesian taggingIndonesian : taggingIndonesians) {
            tmp.setId(taggingIndonesian.getId());
            tmp.setUsingBy(userId);
            indonesianMapper.updateSelective(tmp);
        }
    }

    @Override
    public List<TaggingIndonesian> queryByTimePeriod(LocalDateTime startTime, LocalDateTime endTime, int mode) {
        return indonesianMapper.queryByTimePeriod(startTime, endTime, mode);
    }

//    private static List<String> abbreviationList;
//    private static List<String> abbreviationCompleteList;
//    private static List<String> abbreviationCompleteChineseList;
//    private static List<String> abbreviationCompleteManualList;
    private static List<String> unknownWordList;
    private static List<String> unknownWordCategoryList;
    private static List<String> unknownWordRemarkList;
    private static List<String> unknownWordCorrectList;
    private static Set<String> skipFields;

    static {
//        abbreviationList = new LinkedList<>();
//        abbreviationCompleteList = new LinkedList<>();
//        abbreviationCompleteChineseList = new LinkedList<>();
//        abbreviationCompleteManualList = new LinkedList<>();
        unknownWordList = new LinkedList<>();
        unknownWordCategoryList = new LinkedList<>();
        unknownWordRemarkList = new LinkedList<>();
        unknownWordCorrectList = new LinkedList<>();
        skipFields = new HashSet<>();
        skipFields.add("usingBy");
        skipFields.add("updateBy");
        skipFields.add("updateByTranslation");
        skipFields.add("updateByUnknownWord");
        skipFields.add("updateByAbbreviation");
    }

    @Override
    public Workbook constructWorkbookByTimePeriod(LocalDateTime startTime, LocalDateTime endTime, int mode) {
        List<TaggingIndonesian> taggingIndonesians = queryByTimePeriod(startTime, endTime, mode);
        List<AbbreviationIndonesian> abbreviationIndonesians = abbreviationService.queryByTimePeriod(startTime, endTime, mode);
        List<UnknownWordIndonesian> unknownWordIndonesians = unknownWordService.queryByTimePeriod(startTime, endTime, mode);
        Workbook workbook = new HSSFWorkbook();
        Sheet sheet = workbook.createSheet();
        Row row = sheet.createRow(0);
        Map<String, Integer> map = preConstruct(TaggingIndonesian.class, skipFields);
        preConstruct(row, map);

        int i = 1;
        for (TaggingIndonesian t : taggingIndonesians) {
            Row r = sheet.createRow(i++);
            //处理example
            map.forEach((fieldName, index) -> {
                try {
                    Object valueInvoke = valueInvoke(t, fieldName);
                    r.createCell(index).setCellValue(valueInvoke!=null?String.valueOf(valueInvoke):"");
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
            //处理abbreviation
//            List<AbbreviationIndonesian> abs = searchAbbreviationsByTagId(abbreviationIndonesians, t.getId());
//            abs.forEach(each -> {
//                abbreviationList.add(each.getAbbreviation() == null ? "" : each.getAbbreviation());
//                abbreviationCompleteList.add(each.getAbbreviationComplete() == null ? "" : each.getAbbreviationComplete());
//                abbreviationCompleteChineseList.add(each.getAbbreviationCompleteChinese() == null ? "" : each.getAbbreviationCompleteChinese());
//                abbreviationCompleteManualList.add(each.getAbbreviationCompleteManual() == null ? "" : each.getAbbreviationCompleteManual());
//            });
//            String abbreviations = Arrays.toString(abbreviationList.toArray());
//            r.createCell(map.size()).setCellValue(abbreviations);
//            String abbreviationComplete = Arrays.toString(abbreviationCompleteList.toArray());
//            r.createCell(map.size() + 1).setCellValue(abbreviationComplete);
//            String abbreviationCompleteChinese = Arrays.toString(abbreviationCompleteChineseList.toArray());
//            r.createCell(map.size() + 2).setCellValue(abbreviationCompleteChinese);
//            String abbreviationCompleteManual = Arrays.toString(abbreviationCompleteManualList.toArray());
//            r.createCell(map.size() + 3).setCellValue(abbreviationCompleteManual);
//            abbreviationList.clear();
//            abbreviationCompleteList.clear();
//            abbreviationCompleteChineseList.clear();
//            abbreviationCompleteManualList.clear();
            //处理unknownWord
            List<UnknownWordIndonesian> uwis = searchUnknownWordsByTagId(unknownWordIndonesians, t.getId());
            uwis.forEach(each -> {
                unknownWordList.add(each.getUnknownWord() == null ? "" : each.getUnknownWord());
                unknownWordCategoryList.add(each.getCategory() == null ? "" : each.getCategory());
                unknownWordRemarkList.add(each.getRemark() == null ? "" : each.getRemark());
                unknownWordCorrectList.add(each.getUnknownWordCorrect() == null ? "" : each.getUnknownWordCorrect());
            });
            String unknownWords = Arrays.toString(unknownWordList.toArray());
            r.createCell(map.size() + 1).setCellValue(unknownWords);
            String unknownWordCategories = Arrays.toString(unknownWordCategoryList.toArray());
            r.createCell(map.size() + 2).setCellValue(unknownWordCategories);
            String unknownWordRemarks = Arrays.toString(unknownWordRemarkList.toArray());
            r.createCell(map.size() + 3).setCellValue(unknownWordRemarks);
            String unknownWordCorrects = Arrays.toString(unknownWordCorrectList.toArray());
            r.createCell(map.size() + 4).setCellValue(unknownWordCorrects);
            unknownWordList.clear();
            unknownWordCategoryList.clear();
            unknownWordCorrectList.clear();
            unknownWordRemarkList.clear();
        }
        return workbook;
    }

    private List<UnknownWordIndonesian> searchUnknownWordsByTagId(List<UnknownWordIndonesian> unknownWordIndonesians, Integer tagId) {
        if (unknownWordIndonesians.size() == 0) {
            return new ArrayList<>(0);
        }
        int left = 0;
        int right = unknownWordIndonesians.size() - 1;
        int target = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (tagId.equals(unknownWordIndonesians.get(mid).getTagId())) {
                target = mid;
                break;
//                return mid;
            } else if (tagId.compareTo(unknownWordIndonesians.get(mid).getTagId()) > 0) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        if (target == -1) {
            return new ArrayList<>(0);
        }
        //若能找到这个坐标，向其左右延申并记录下来其坐标
        List<UnknownWordIndonesian> targets = new LinkedList<>();
        targets.add(unknownWordIndonesians.get(target));
        int t1 = target;
        while ((t1=t1-1)>0&&unknownWordIndonesians.get(t1).getTagId().equals(unknownWordIndonesians.get(target).getTagId())) {
            targets.add(unknownWordIndonesians.get(t1));
        }
        int t2 = target;
        while ((t2=t2+1)<unknownWordIndonesians.size()&&unknownWordIndonesians.get(t2).getTagId().equals(unknownWordIndonesians.get(target).getTagId())) {
            targets.add(unknownWordIndonesians.get(t2));
        }
        return targets;
    }

    private List<AbbreviationIndonesian> searchAbbreviationsByTagId(List<AbbreviationIndonesian> abbreviationIndonesians, Integer tagId) {
        if (abbreviationIndonesians.size() == 0) {
            return new ArrayList<>();
        }
        int left = 0;
        int right = abbreviationIndonesians.size() - 1;
        int target = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (tagId.equals(abbreviationIndonesians.get(mid).getTagId())) {
                target = mid;
                break;
//                return mid;
            } else if (tagId.compareTo(abbreviationIndonesians.get(mid).getTagId()) > 0) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        if (target == -1) {
            return new ArrayList<>(0);
        }
        //若能找到这个坐标，向其左右延申并记录下来其坐标
        List<AbbreviationIndonesian> targets = new LinkedList<>();
        targets.add(abbreviationIndonesians.get(target));
        int t1 = target;
        while ((t1=t1-1)>0&&abbreviationIndonesians.get(t1).getTagId().equals(abbreviationIndonesians.get(target).getTagId())) {
            targets.add(abbreviationIndonesians.get(t1));
        }
        int t2 = target;
        while ((t2=t2+1)<abbreviationIndonesians.size()&&abbreviationIndonesians.get(t2).getTagId().equals(abbreviationIndonesians.get(target).getTagId())) {
            targets.add(abbreviationIndonesians.get(t2));
        }
        return targets;
    }

    private Object valueInvoke(TaggingIndonesian t, String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = t.getClass().getMethod("get" + toCapital(fieldName));
        return method.invoke(t);
    }

    private void preConstruct(Row r, Map<String, Integer> map) {
        map.forEach((field, index) -> {
            r.createCell(index).setCellValue(field);
        });
//        r.createCell(map.size()).setCellValue("abbreviation");
//        r.createCell(map.size() + 1).setCellValue("abbreviationComplete");
//        r.createCell(map.size() + 2).setCellValue("abbreviationCompleteChinese");
//        r.createCell(map.size() + 3).setCellValue("abbreviationCompleteManual");
        r.createCell(map.size() + 4).setCellValue("unknownWords");
        r.createCell(map.size() + 5).setCellValue("unknownWordCategories");
        r.createCell(map.size() + 6).setCellValue("unknownWordRemarks");
        r.createCell(map.size() + 7).setCellValue("unknownWordCorrects");
    }

}
